package com.djhu.hadoop.fileservice;

import com.djhu.hadoop.BasicFileInfo;
import com.djhu.hadoop.DefaultFileNameGenerator;
import com.djhu.hadoop.FileNameGenerator;
import com.djhu.hadoop.xmlreader.FormatXmlReader;
import com.djhu.hadoop.xmlreader.XmlReader;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class CacheFileService implements FileService,InitializingBean {
    private static final Log logger = LogFactory.getLog(LocalFileService.class);

    //外层key 为 dir  内层key为file
    private Map<String,Map<String, BasicFileInfo>> fileCache = null;

    private FileService fileService;

    private FileNameGenerator fileNameGenerator;

    private XmlReader xmlReader;

    //缓存中多少个文件
    private int fileCacheSize = 10;

    private String defaultDir = "./file/";
    private String filename = "xmlfile";

    private List<BasicFileInfo> fileInfos = new ArrayList<>();
    private long maxFileSize = 1024 * 1024; //128M

    //private ExecutorService executorService = Executors.newFixedThreadPool(10);

    private synchronized BasicFileInfo selectOneFile(Map<String,Map<String, BasicFileInfo>> fileCache,String remoteDir) {
        if (fileCache.isEmpty()) {
            return null;
        }
        if (StringUtils.isEmpty(remoteDir)){
            remoteDir = defaultDir;
        }
        if (!fileCache.containsKey(remoteDir)){
            initCache(remoteDir,fileCacheSize);
        }

        Map<String, BasicFileInfo> dirFileCache = fileCache.get(remoteDir);
        if (dirFileCache.isEmpty()){
            return null;
        }
        int pos = Math.abs(new Random(System.currentTimeMillis()).nextInt() % dirFileCache.size());
        int index = 0;
        for (Map.Entry<String, BasicFileInfo> entry : dirFileCache.entrySet()) {
            if (index == pos) {
                String key = entry.getKey();
                BasicFileInfo basicFileInfo = dirFileCache.remove(key);
                return basicFileInfo;
            }
            index++;
        }
        return null;
    }

    @Override
    public BasicFileInfo upload(String string, String remote) {
        //如果找到的另外的内容 超过了最大阈值 ，那么 将该信息移至已完成列表中
        //然后重新选择
        return upload(string.getBytes(),remote);
    }


    @Override
    public BasicFileInfo doanload(BasicFileInfo basicFileInfo) {
        return fileService.doanload(basicFileInfo);
    }

    public  void initCache(String dir,int fileCacheSize){
        Map<String,BasicFileInfo> fileInfoMap = new HashMap<>();
        for (int i = 0; i < fileCacheSize; i++) {
            String generateFilename = fileNameGenerator.generateName(dir, filename);
            if (!fileInfoMap.containsKey(generateFilename)) {
                fileInfoMap.put(generateFilename, new BasicFileInfo(generateFilename, 0L, 0L));
            }
        }
        fileCache.put(dir,fileInfoMap);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (fileCache == null || fileCache.size() == 0) {
            fileCache = new ConcurrentHashMap<>();
            initCache(defaultDir,fileCacheSize);
        }
    }

    @Override
    public BasicFileInfo upload(File file, String remote) {
        String xml = xmlReader.readXml(file);
        xml = xml.concat(System.getProperty("line.separator"));
        BasicFileInfo basicFileInfo = upload(xml, remote);
        basicFileInfo.setLocalFile(file.getAbsolutePath());
        return basicFileInfo;
    }

    @Override
    public BasicFileInfo upload(byte[] bytes, String remote) {
        if (StringUtils.isEmpty(remote)){
            remote = defaultDir;
        }
        BasicFileInfo remoteFile = null;
        while (true) {
            remoteFile = selectOneFile(fileCache,remote);
            //如果为空  说明文件都在进行读写
            if (remoteFile == null) {
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                    continue;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //如果选择出来的文件大小 小于 阈值，那么直接跳出
            if (remoteFile.getStart() + remoteFile.getLength() < maxFileSize) {
                break;
            } else {
                //如果选择出来的文件大于阈值 ，那么 将文件一到完成列表中
                //重新生成一个文件
                BasicFileInfo basicFileInfo = new BasicFileInfo(remoteFile.getRemoteFile(), remoteFile.getStart(), remoteFile.getLength());
                fileInfos.add(basicFileInfo);

                String generateFilename = fileNameGenerator.generateName(remote, filename);
                remoteFile = new BasicFileInfo(generateFilename, 0L, 0L);
                //判断缓存中是否存在该文件 不存在进行读写  存在那么重新选择
                if (!fileCache.containsKey(generateFilename)) {
                    break;
                } else {
                    continue;
                }
            }
        }
        logger.debug("select one remote file ,file is " + remoteFile.toString());

        BasicFileInfo basicFileInfo = fileService.upload(bytes, remoteFile.getRemoteFile());
        //将新文件加入缓存中
        fileCache.get(remote).put(basicFileInfo.getRemoteFile(), basicFileInfo);
        return basicFileInfo;
    }

    @Override
    public byte[] readBytes(BasicFileInfo basicFileInfo) {
        return fileService.readBytes(basicFileInfo);
    }

    public FileService getFileService() {
        return fileService;
    }

    public void setFileService(FileService fileService) {
        this.fileService = fileService;
    }

    public FileNameGenerator getFileNameGenerator() {
        return fileNameGenerator;
    }

    public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
        this.fileNameGenerator = fileNameGenerator;
    }

    public XmlReader getXmlReader() {
        return xmlReader;
    }

    public void setXmlReader(XmlReader xmlReader) {
        this.xmlReader = xmlReader;
    }


    public int getFileCacheSize() {
        return fileCacheSize;
    }

    public void setFileCacheSize(int fileCacheSize) {
        this.fileCacheSize = fileCacheSize;
    }

    public String getDefaultDir() {
        return defaultDir;
    }

    public void setDefaultDir(String defaultDir) {
        this.defaultDir = defaultDir;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public long getMaxFileSize() {
        return maxFileSize;
    }

    public void setMaxFileSize(long maxFileSize) {
        this.maxFileSize = maxFileSize;
    }

    public static void main(String[] args) throws Exception {

        LocalFileService localFileService = new LocalFileService();
        CacheFileService cacheFileService = new CacheFileService();
        cacheFileService.setFileService(localFileService);
        FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
        cacheFileService.setFileNameGenerator(fileNameGenerator);
        XmlReader xmlReader = new FormatXmlReader();
        cacheFileService.setXmlReader(xmlReader);
        cacheFileService.afterPropertiesSet();
        File file = new File("./1.2.3.4.111.111.1.xml");
        for (int i = 0; i < 1000; i++) {

            cacheFileService.upload(file, null);
        }
    }
}



